/*
         This file is part of KIP.
     KIP is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
     the Free Software Foundation, either version 3 of the License, or
     (at your option) any later version.
     KIP is distributed in the hope that it will be useful,
     but WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     GNU General Public License for more details.
 */
 #include "config.h"
 #include "contrib/net.h"
 #include "contrib/enc28j60.h"
 #include "contrib/ip_arp_udp.h"
 #include "adc_read.h"
 #include <avr/io.h>
 #include <stdint.h>           // for uint8_t etc
 #include <avr/interrupt.h>    // for interrupts    
#define BUFFER_SIZE 600
 
void init_leds()
 {
     int i;
     DDRD |= (1 << LED_GREEN);
     DDRD |= (1 << LED_RED);
     PORTD |= 1 << LED_RED;
     for(i =0; i < 5; i++)
     {
         PORTD ^= 1 << LED_RED;
         PORTD ^= 1 << LED_GREEN;
         _delay_ms(500);
     }
 }
 
void init_mac()
 {
     enc28j60Init(config_object.mac);
     _delay_ms(100);
     /* Magjack leds configuration, see enc28j60 datasheet, page 11 */
     enc28j60PhyWrite(PHLCON,0x476);
     /* set output to GND, red LED on */
     PORTD |= 1 << LED_GREEN;
         init_ip_arp_udp(config_object.mac,config_object.ip);
 }
 
uint8_t handle_ping_arp(uint8_t *buf, uint16_t plen)
 {
     // arp is broadcast if unknown but a host may also
     // verify the mac address by sending it to
     // a unicast address.
     if(eth_type_is_arp_and_my_ip(buf,plen)) {
         make_arp_answer_from_request(buf,plen);
         return 1;
     }
     // check if ip packets (icmp or udp) are for us:
     if(eth_type_is_ip_and_my_ip(buf,plen)==0) {
         return 1;
     }
     if(buf[IP_PROTO_P]==IP_PROTO_ICMP_V && buf[ICMP_TYPE_P]==ICMP_TYPE_ECHOREQUEST_V) {
         // a ping packet, let's send pong
         make_echo_reply_from_request(buf,plen);
         return 1;
     }
     return  0;
 }
 
int main()

{
    uint8_t buf[BUFFER_SIZE+1];
    uint16_t plen;
    uint8_t payloadlen=0;
    uint8_t i;
    uint8_t* adc;
    uint8_t state=0;
    init_leds();
    load_config();
    init_adc();
    _delay_ms(100);
    init_mac();
    _delay_ms(100);      
    PCICR |= (1 << PCIE0);
    //PCICR Bits 3 4 5 6 7 are reserve bits
    //PCIE2 is bit 2 = PCINT23...16
    //PCIE1 is bit 1 = PCINT14...8
    //PCIE0 is bit 0 = PCINT7...0  <-- expecting interrupt on one of these particular 8 pins
    PCMSK0 |= (1 << PCINT3);   // set PCINT3 to trigger an interrupt on state change 
    //Enable Interrupt on just PCINT3s
    //PCMSK0 states which PCINT7...0 is enabled 
     sei();// turn on global interrupts (SREG bit 7)
    //SREG Bit 7 is Global Interrupt Enable = sei() changes just bit 7   
    
    while(1)
     {
         switch(state)
          {
            default:
                  break;
           
           case 1:
                 // get the next new packet:
                plen = enc28j60PacketReceive(BUFFER_SIZE, buf);
                /*plen will ne unequal to zero if there is a valid
                * packet (without crc error) */
                if(plen==0)
                {
                continue;
                }
                if(handle_ping_arp(buf, plen))
                continue;
                if (buf[IP_PROTO_P]==IP_PROTO_UDP_V)
                {
                payloadlen=buf[UDP_LEN_L_P]-UDP_HEADER_LEN;
                if(payloadlen != 11) //Mallformed command.
                        continue;
                if (buf[UDP_DATA_P]== 0xBC)
                        {
                        switch(buf[UDP_DATA_P + 1])
                            {
                            case 1:
                                  adc = adc_read(config_object.sampleDelay);
                                  make_udp_reply_from_request(buf,adc,ADC_PACKET_SIZE ,config_object.port);
                                  PORTD ^= 1 << LED_RED;                   
                                  break;
                                                         
                            case 2:
                                  //set the id.
                                  config_object.id = buf[UDP_DATA_P + 2] ;
                                  break;
                                                         
                            case 3:
                                  //set ip.
                                  for(i= 0; i< 4; i++)
                                         config_object.ip[i] = buf[UDP_DATA_P + 3 +i];
                                  break;
                                                         
                            case 4:
                                  //set mac
                                  for(i= 0; i< 6; i++)
                                         config_object.mac[i] = buf[UDP_DATA_P + 3 +i];
                                  break;
                                                         
                            case 5:
                                  //set sample delay
                                  config_object.sampleDelay = buf[UDP_DATA_P + 2];
                                  break;
                                                                       
                            case 0xF:
                                  store_config();
                                  init_mac();
                                  break;
                                                         
                            default:
                                  //Mallformed command.
                                  break;
                            }
                        }
                }
                break;
          }
     }
}

ISR (PCINT0_vect)
//PCINT0_vect is for PCINT5...0
//PCINT1_vect is for PCINT13...8
//PCINT2_vect is for PCINT23...16
{
    //will go to state 1 until stops recieving on PB3
    if(PORTB & (1 << PB3))
    {
        //LOW to HIGH: rising edge
        state = 1;
    }
    else
    {
        //HIGH to LOW: falling edge
        state = 0;
        
    }
}
